package com.demo3;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.file.linux.AndroidFileIO;
import com.github.unidbg.linux.android.*;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.api.ApplicationInfo;
import com.github.unidbg.linux.android.dvm.api.ClassLoader;
import com.github.unidbg.linux.android.dvm.api.SystemService;
import com.github.unidbg.linux.android.dvm.array.ArrayObject;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.linux.file.ByteArrayFileIO;
import com.github.unidbg.linux.file.DirectoryFileIO;
import com.github.unidbg.linux.file.SimpleFileIO;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.unix.UnixSyscallHandler;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import com.utils.SearchAesKey;
import unicorn.Arm64Const;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.io.*;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class WToken extends AbstractJni implements IOResolver {
    @Override
    public FileResult resolve(Emulator emulator, String pathname, int oflags) {
        System.out.println("file open:"+pathname);
        if(pathname.contains("status")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/files/status"), pathname));
        }
        if(pathname.equals("/proc/./cmdline")){
            return FileResult.success(new ByteArrayFileIO(oflags, pathname, "ramoops_memreserve=4M rcupdate.rcu_expedited=1 console=ttyMSM0,115200n8 earlycon=msm_geni_serial,0xA84000 androidboot.hardware=qcom androidboot.console=ttyMSM0 video=vfb:640x400,bpp=32,memsize=3072000 msm_rtb.filter=0x237 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 service_locator.enable=1 swiotlb=2048 androidboot.configfs=true loop.max_part=7 androidboot.usbcontroller=a600000.dwc3 buildvariant=user root=/dev/dm-0 dm=\"system none ro,0 1 android-verity /dev/sde48\" androidboot.verifiedbootstate=orange androidboot.keymaster=1  androidboot.veritymode=enforcing androidboot.bootdevice=1d84000.ufshc androidboot.serialno=f8a995f5 androidboot.baseband=msm msm_drm.dsi_display0=dsi_jdi_fhd_nt35596s_video_display: androidboot.ramdump=disable androidboot.secureboot=1 androidboot.dp=0x0 androidboot.cpuid=0xe901525e androidboot.hwversion=2.4.0 androidboot.hwc=CN androidboot.cert=M1803D5XE androidboot.hwlevel=MP androidboot.dtb_idx=-1347440721".getBytes(StandardCharsets.UTF_8)));
        }
        if(pathname.equals("/data")){
            return FileResult.success(new DirectoryFileIO(oflags, pathname, new File("unidbg-android/src/test/resources/demo3/files/data")));
        }
        if(pathname.equals("/data/user/0/com.nike.omega")){
            return FileResult.success(new DirectoryFileIO(oflags, pathname, new File("unidbg-android/src/test/resources/demo3/files/omega")));
        }
        if(pathname.equals("getprop")){
            return FileResult.success(new ByteArrayFileIO(oflags, pathname, "29".getBytes(StandardCharsets.UTF_8)));
        }
        if(pathname.equals("uname")){
            return FileResult.success(new ByteArrayFileIO(oflags, pathname, "Linux localhost 4.9.186-perf-gd3d6708 #1 SMP PREEMPT Wed Nov 4 01:05:59 CST 2020 aarch64".getBytes(StandardCharsets.UTF_8)));
        }
        if(pathname.contains(".ac3af9")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/files/ac3af9.txt"), pathname));
        }
        if(pathname.equals("/system/lib/libdl.so")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/files/libdl.so"), pathname));
        }
        if(pathname.equals("/system/bin/linker")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/files/linker"), pathname));
        }
        if(pathname.equals("/etc/hosts")){
            return FileResult.success(new ByteArrayFileIO(oflags, pathname, "127.0.0.1       localhost".getBytes(StandardCharsets.UTF_8)));
        }
        if(pathname.equals("/data/app/com.nike.omega-66wMdXYGOqj0QXJz8qMSyQ==/base.apk")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/apk/com.nike.omega_22.29.2_2012212030.apk"), pathname));
        }
        if(pathname.equals("/proc/cpuinfo")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/files/cpuinfo"), pathname));
        }
        if(pathname.equals("/proc/version")){
            return FileResult.success(new ByteArrayFileIO(oflags, pathname, "Linux version 4.9.186-perf-gd3d6708 (builder@c3-miui-ota-bd134.bj) (gcc version 4.9.x 20150123 (prerelease) (GCC) ) #1 SMP PREEMPT Wed Nov 4 01:05:59 CST 2020".getBytes(StandardCharsets.UTF_8)));
        }
        if(pathname.contains("comm")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/files/comm.txt"), pathname));
        }
        if(pathname.equals("/proc/stat")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo3/files/stat"), pathname));
        }
        return null;
    }

    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    private final DvmClass TigerTallyAPI;
    private final String alttPath = "unidbg-android/src/test/resources/demo3/files/alttTable.txt";

    public void destroy() throws IOException {
        emulator.close();
    }

    public WToken(){
        String appPath = "unidbg-android/src/test/resources/demo3/apk/com.nike.omega_22.29.2_2012212030.apk";
        // 创建模拟器实例
        AndroidEmulatorBuilder builder = new AndroidEmulatorBuilder(true){
            @Override
            public AndroidEmulator build() {
                return new AndroidARM64Emulator(processName,rootDir,backendFactories) {
                    @Override
                    protected UnixSyscallHandler<AndroidFileIO> createSyscallHandler(SvcMemory svcMemory) {
                        return new tigerSyscallHandler(svcMemory);
                    }
                };
            }
        };
        emulator = builder.
                addBackendFactory(new Unicorn2Factory(false)).
                setProcessName("com.nike.omega").
                setRootDir(new File("unidbg-android/src/test/resources/demo3/rootfs")).
                build();

        final Memory memory = emulator.getMemory(); // 模拟器的内存操作接口

        emulator.getSyscallHandler().setEnableThreadDispatcher(true);
        emulator.getBackend().registerEmuCountHook(10000); // 设置执行多少条指令切换一次线程
        memory.setLibraryResolver(new AndroidResolver(23)); // 设置系统类库解析

        emulator.getSyscallHandler().addIOResolver(this);
        vm = emulator.createDalvikVM(new File(appPath)); // 创建Android虚拟机

        // libandroid.so 虚拟模块
        new AndroidModule(emulator, vm).register(memory);

        // 一些不得不处理的 JAVA 类库
        vm.resolveClass("com/aliyun/TigerTally/A$BB", vm.resolveClass("com/aliyun/TigerTally/A$AA"));
        vm.addNotFoundClass("com/aliyun/TigerTally/NaitveAPI");

        SystemPropertyHook systemPropertyHook = new SystemPropertyHook(emulator);
        systemPropertyHook.setPropertyProvider(new SystemPropertyProvider() {
            @Override
            public String getProperty(String key) {
                System.out.println("lilac systemkey:" + key);
                switch (key) {
                    case "ro.bootloader":{
                        return "unknown";
                    }
                    case "ro.secure":{
                        return "1";
                    }
                    case "net.hostname":{
                        return "MIX2S-M";
                    }
                    case "ro.serialno":{
                        return "f8a995f5";
                    }
                    case "ro.boot.serialno":{
                        return "f8a995f5";
                    }
                    case "ro.product.brand":{
                        return "Xiaomi";
                    }
                    case "ro.product.manufacturer":{
                        return "Xiaomi";
                    }
                    case "ro.product.model":{
                        return "MIX 2S";
                    }
                    case "ro.product.cpu.abi":{
                        return "arm64-v8a";
                    }
                    case "ro.product.cpu.abilist":{
                        return "arm64-v8a,armeabi-v7a,armeabi";
                    }
                    case "ro.boot.vbmeta.digest":{
                        return null;
                    }
                    case "init.svc.droid4x":{
                        return null;
                    }
                    case "ro.build.version.sdk":{
                        return "29";
                    }
                    case "debug.atrace.tags.enableflags":{
                        return "0";
                    }
                }
                return "";
            };
        });
        memory.addHookListener(systemPropertyHook);


        DalvikModule dm = vm.loadLibrary("tiger_tally", true); // 加载so到虚拟内存
        module = dm.getModule(); //获取本SO模块的句柄
        vm.setJni(this);
        vm.setVerbose(true);

        dm.callJNI_OnLoad(emulator);
        TigerTallyAPI = vm.resolveClass("com/aliyun/TigerTally/TigerTallyAPI");

        hookBind();
        hookPopen();

//        ArrayList<String> funclist = SearchAesKey.readFuncFromIDA("unidbg-android/src/test/resources/demo3/apk/libtiger_tally_functionlist_1666569690.txt");
//        SearchAesKey aesKeyFinder = new SearchAesKey(emulator);
//        aesKeyFinder.searchEveryFunction(module.base, funclist);
    }

    private void hookPopen() {
        emulator.attach().addBreakPoint(module.findSymbolByName("popen").getAddress(), new BreakPointCallback() {
            UnidbgPointer psptr = UnidbgPointer.pointer(emulator, module.findSymbolByName("fopen").call(emulator, "getprop", "r"));
            UnidbgPointer unameptr = UnidbgPointer.pointer(emulator, module.findSymbolByName("fopen").call(emulator, "uname", "r"));
            @Override
            public boolean onHit(Emulator<?> emulator, long address) {
                System.out.println("SO call popen");
                RegisterContext registerContext = emulator.getContext();
                String cmd = registerContext.getPointerArg(0).getString(0);
                System.out.println("popen arg:"+cmd);
                emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_PC, emulator.getContext().getLRPointer().peer);
                if(cmd.contains("ps")){
                    emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0, 0);
                    return true;
                }
                if(cmd.contains("getprop ro.build.version.sdk")){
                    emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0, psptr.peer);
                    return true;
                }
                if(cmd.equals("uname -a")){
                    emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0, unameptr.peer);
                    return true;
                }
                return false;
            }
        });
    }

    public void init(){
        TigerTallyAPI.callStaticJniMethodInt(emulator, "_genericNt2(ILjava/lang/String;)I", 2, "j0m4PjXNgOX_A_ZJXjBNgJ0DRtp_VQWwEMS5DkAJUJsKPR-0r8PqOkWMrhwymjZCoyOzBW2aqkrY8Tw9Cbwyl9fMOlOMPTC7_sOho2t_mOpdhkcQrWAc8fv_EATLX5DSrlve4QlMpMZtIuTfry6bm4VRSapMNRLn_dOCZ06VbLQ=");
        System.out.println("call init 1 over");
        int result = TigerTallyAPI.callStaticJniMethodInt(emulator, "_genericNt1(I)I", -1);
        System.out.println("init result:"+result);
    }

    public void callTarget(){
//        ArrayList<String> funclist = SearchAesKey.readFuncFromIDA("unidbg-android/src/test/resources/demo3/apk/libtiger_tally_functionlist_1666569690.txt");
//        SearchAesKey aesKeyFinder = new SearchAesKey(emulator);
//        aesKeyFinder.searchEveryFunction(module.base, funclist);

        DvmObject<?> dvmObject = TigerTallyAPI.callStaticJniMethodObject(emulator, "_genericNt3(I[B)Ljava/lang/String;", 1, new ByteArray(vm, "b3872cce-c4a7-43b1-8a22-b6562dcf78d8".getBytes(StandardCharsets.UTF_8)));
        String wtoken = dvmObject.getValue().toString();
        System.out.println("result:"+wtoken);
    }

    public static void main(String[] args) {
        WToken wt = new WToken();
        wt.init();
        wt.callTarget();
    }

    @Override
    public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature){
            case "com/aliyun/TigerTally/A->ct()Landroid/content/Context;":{
                return vm.resolveClass("com.nike.mynike.MyNikeApplication").newObject(null);
            }
            case "com/aliyun/TigerTally/A->bt()Landroid/content/Intent;":{
                return vm.resolveClass("android/content/Intent").newObject("android.intent.action.BATTERY_CHANGED");
            }
            case "java/lang/System->getProperty(Ljava/lang/String;)Ljava/lang/String;": {
                String key = vaList.getObjectArg(0).getValue().toString();
                System.out.println("fuck key:"+key);
                switch (key) {
                    case "http.proxyHost": {
                        return null;
                    }
                    case "http.proxyPort": {
                        return null;
                    }
                    case "http.agent":
                        return new StringObject(vm, "Dalvik/2.1.0 (Linux; U; Android 10; MIX 2S MIUI/V12.0.2.0.QDGCNXM)");
                }
            }
            case "java/net/NetworkInterface->getNetworkInterfaces()Ljava/util/Enumeration;":{
                // 真实情况这个数组要长很多
                String[] NetworkInterfaceNameList = new String[]{"dummy0", "r_rmnet_data2", "r_rmnet_data3", "ip_vti0", "wlan0", "wlan1"};
                int length = NetworkInterfaceNameList.length;
                List<DvmObject<?>> NetworkInterfacelist = new ArrayList<>();
                for (int i = 0; i < length; i++) {
                    NetworkInterfacelist.add(vm.resolveClass("java/net/NetworkInterface").newObject(NetworkInterfaceNameList[i]));
                }
                return new Enumeration(vm, NetworkInterfacelist);
            }
            case "java/util/Collections->list(Ljava/util/Enumeration;)Ljava/util/ArrayList;":
                ArrayListObject arrayListObject = new ArrayListObject(vm,
                        (List<? extends DvmObject<?>>) vaList.getObjectArg(0).getValue());
                return arrayListObject;
            case "java/lang/ClassLoader->getSystemClassLoader()Ljava/lang/ClassLoader;":{
                return vm.resolveClass("dalvik.system.PathClassLoader").newObject(null);
            }
            case "java/lang/Class->forName(Ljava/lang/String;)Ljava/lang/Class;":{
                String className = vaList.getObjectArg(0).getValue().toString();
                return vm.resolveClass(className).newObject(null);
            }
            case "android/provider/Settings$Secure->getString(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;":{
                String tag = vaList.getObjectArg(1).getValue().toString();
                System.out.println("Settings$Secure->getString:"+tag);
                switch (tag){
                    // http://www.ccbu.cc/index.php/framework/modify-default-inputmethod.html
                    case "default_input_method":{
                        return new StringObject(vm, "com.android.inputmethod.pinyin/.InputService");
                    }
                    case "android_id":{
                        // 自行设置
                        return new StringObject(vm, "");
                    }
                }
            }
            case "com/aliyun/TigerTally/A->am()Ljava/lang/String;":{
                return new StringObject(vm, "android.app.IActivityManager$Stub$Proxy|android.os.BinderProxy");
            }
            case "android/os/Environment->getExternalStorageState()Ljava/lang/String;":{
                return new StringObject(vm, "mounted");
            }
            case "android/os/Environment->getExternalStorageDirectory()Ljava/io/File;":{
                return vm.resolveClass("java/io/File").newObject("/storage/emulated/0");
            }
            case "android/net/Uri->parse(Ljava/lang/String;)Landroid/net/Uri;":{
                return null;
            }
            case "android/os/Environment->getDataDirectory()Ljava/io/File;":{
                return vm.resolveClass("java/io/File").newObject("/data");
            }
            case "com/aliyun/TigerTally/A->pb(Ljava/lang/String;[B)Ljava/lang/String;":
                String arg1 = vaList.getObjectArg(0).getValue().toString();
                byte[] bytes = (byte[]) vaList.getObjectArg(1).getValue();
                String ret = utils.pb(arg1, bytes);
                System.out.println("PB result:"+ret);
                return new StringObject(vm,ret);
        }
        return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
    }

    @Override
    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        if(signature.contains("getDeclaredMethod")){
            return vm.resolveClass("java/lang/reflect/Method").newObject(null);
        }
        switch (signature){
            case "com/nike/mynike/MyNikeApplication->getPackageName()Ljava/lang/String;":{
                return new StringObject(vm, vm.getPackageName());
            }
            case "com/nike/mynike/MyNikeApplication->getPackageManager()Landroid/content/pm/PackageManager;":{
                return vm.resolveClass("android/content/pm/PackageManager").newObject(null);
            }
            // Nike 耐克
            case "android/content/pm/PackageManager->getApplicationLabel(Landroid/content/pm/ApplicationInfo;)Ljava/lang/CharSequence;":{
                CharSequence b = "Nike 耐克";
                return ProxyDvmObject.createObject(vm, b);
            }
            case "com/nike/mynike/MyNikeApplication->getFilesDir()Ljava/io/File;":{
                return vm.resolveClass("java/io/File").newObject("/data/user/0/com.nike.omega/files");
            }
            case "java/io/File->getAbsolutePath()Ljava/lang/String;":{
                return new StringObject(vm, dvmObject.getValue().toString());
            }
            case "com/nike/mynike/MyNikeApplication->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;":{
                return vm.resolveClass("android/content/SharedPreferences").newObject(null);
            }
            case "android/content/SharedPreferences->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;":{
                String key = vaList.getObjectArg(0).getValue().toString();
                System.out.println("getKey:"+key);
                return new StringObject(vm, readAlttSP(key));
            }
            case "java/net/NetworkInterface->getName()Ljava/lang/String;":{
                return new StringObject(vm, dvmObject.getValue().toString());
            }
            case "dalvik/system/PathClassLoader->loadClass(Ljava/lang/String;)Ljava/lang/Class;": {
                String className = vaList.getObjectArg(0).getValue().toString();
                switch (className) {
                    case "de.robv.android.xposed.XposedBridge":
                        emulator.getDalvikVM().throwException(vm.resolveClass("java/lang/NoClassDefFoundError").newObject(className));
                        return null;
                }
            }
            case "com/nike/mynike/MyNikeApplication->createPackageContext(Ljava/lang/String;I)Landroid/content/Context;": {
                String packageName = vaList.getObjectArg(0).getValue().toString();
                System.out.println(packageName);
                if (packageName.equals("io.va.exposed64")) {
                    return null;
                }
                if (packageName.equals("io.va.exposed")) {
                    return null;
                }
            }
            case "android/provider/Settings$System->getDeclaredMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;":{
                return vm.resolveClass("java/lang/reflect/Method").newObject(null);
            }
            case "android/content/SharedPreferences$Editor->getDeclaredMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;":{
                return vm.resolveClass("java/lang/reflect/Method").newObject(null);
            }
            case "com/nike/mynike/MyNikeApplication->getSystemService(Ljava/lang/String;)Ljava/lang/Object;":{
                if(vaList.getObjectArg(0).getValue().toString().equals("phone_msim")){
                    return vm.resolveClass("android.telephony.MSimTelephonyManager").newObject(null);
                }
                return new SystemService(vm, vaList.getObjectArg(0).getValue().toString());
            }
            case "com/nike/mynike/MyNikeApplication->getContentResolver()Landroid/content/ContentResolver;":{
                return vm.resolveClass("android/content/ContentResolver").newObject(null);
            }
            case "com/nike/mynike/MyNikeApplication->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;":{
                return vm.resolveClass("android/content/Intent").newObject(null);
            }
            case "com/nike/mynike/MyNikeApplication->getApplicationInfo()Landroid/content/pm/ApplicationInfo;":{
                return new ApplicationInfo(vm);
            }
            case "com/nike/mynike/MyNikeApplication->getClassLoader()Ljava/lang/ClassLoader;":{
                return new ClassLoader(vm, null);
            }
            case "dalvik/system/PathClassLoader->getParent()Ljava/lang/ClassLoader;":{
                return vm.resolveClass("java/lang/ClassLoader").newObject(null);
            }
            case "com/aliyun/TigerTally/A$AA->en(Ljava/lang/String;)Ljava/lang/String;":{
                String p0 = vaList.getObjectArg(0).getValue().toString();
                String ret;
                try{
                    ret = new BigInteger(1, MessageDigest.getInstance("md5").digest(p0.getBytes(StandardCharsets.UTF_8))).toString(16);
                }catch(Exception e3){
                    ret = "";
                }
                return new StringObject(vm, ret);
            }
            case "javax/crypto/Cipher->doFinal([B)[B":{
                Cipher cipher = (Cipher) dvmObject.getValue();
                ByteArray byteArray = vaList.getObjectArg(0);
                try {
                    return new ByteArray(vm, cipher.doFinal(byteArray.getValue()));
                } catch (IllegalBlockSizeException | BadPaddingException e) {
                    e.printStackTrace();
                }
                return null;
            }
            case "com/nike/mynike/MyNikeApplication->getExternalFilesDir(Ljava/lang/String;)Ljava/io/File;":{
                return vm.resolveClass("java/io/File").newObject(signature);
            }
            case "java/io/File->toString()Ljava/lang/String;":{
                return new StringObject(vm, "/storage/emulated/0/Android/data/com.nike.omega/files");
            }
            case "android/content/SharedPreferences->edit()Landroid/content/SharedPreferences$Editor;":{
                return vm.resolveClass("android/content/SharedPreferences$Editor").newObject(null);
            }
            case "android/content/SharedPreferences$Editor->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;":{
                String arg1 = vaList.getObjectArg(0).getValue().toString();
                String arg2 = vaList.getObjectArg(1).getValue().toString();
                System.out.println("putString:"+arg1);
                System.out.println("value:"+arg2);
                writeAlttSP(arg1, arg2);
                return dvmObject;
            }
            case "java/net/NetworkInterface->getInetAddresses()Ljava/util/Enumeration;":{
                List<DvmObject<?>> obj = new ArrayList<>();
                return new Enumeration(vm,  obj);
            }
            case "android/telephony/TelephonyManager->getNetworkCountryIso(I)Ljava/lang/String;":{
                return new StringObject(vm, "cn");
            }
            case "android/telephony/TelephonyManager->getNetworkOperatorName(I)Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/TelephonyManager->getNetworkOperator(I)Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/TelephonyManager->getSimOperatorName(I)Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/MSimTelephonyManager->getNetworkCountryIso(I)Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/TelephonyManager->getNetworkCountryIso()Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/MSimTelephonyManager->getNetworkOperatorName(I)Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/MSimTelephonyManager->getNetworkOperator(I)Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/MSimTelephonyManager->getSimOperatorName(I)Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/TelephonyManager->getNetworkOperatorName()Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/TelephonyManager->getNetworkOperator()Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "android/telephony/TelephonyManager->getSimOperatorName()Ljava/lang/String;":{
                return new StringObject(vm, "");
            }
            case "java/io/File->getPath()Ljava/lang/String;":{
                return new StringObject(vm, "/data");
            }
            case "com/nike/mynike/MyNikeApplication->getPackageCodePath()Ljava/lang/String;":{
                return new StringObject(vm, "/data/app/com.nike.omega-66wMdXYGOqj0QXJz8qMSyQ==/base.apk");
            }
            case "android/view/WindowManager->getDefaultDisplay()Landroid/view/Display;":{
                return vm.resolveClass("android/view/Display").newObject(null);
            }
            case "com/nike/mynike/MyNikeApplication->getResources()Landroid/content/res/Resources;":{
                return vm.resolveClass("android/content/res/Resources").newObject(null);
            }
            case "android/content/SharedPreferences$Editor->putInt(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor;":{
                String key = vaList.getObjectArg(0).getValue().toString();
                writeAlttSP(key, String.valueOf(vaList.getIntArg(1)));
                return dvmObject;
            }
        }
        return super.callObjectMethodV(vm, dvmObject, signature, vaList);
    }

    @Override
    public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
        switch (signature) {
            case "android/os/Build->BRAND:Ljava/lang/String;":
                return new StringObject(vm, "Xiaomi");
            case "android/os/Build->MODEL:Ljava/lang/String;":
                return new StringObject(vm, "MIX 2S");
            case "android/os/Build$VERSION->RELEASE:Ljava/lang/String;":
                return new StringObject(vm, "10");
            case "android/os/Build->DEVICE:Ljava/lang/String;":
                return new StringObject(vm, "polaris");
            case "android/os/Build->PRODUCT:Ljava/lang/String;":
                return new StringObject(vm, "walleye");
            case "android/os/Build->HOST:Ljava/lang/String;":
                return new StringObject(vm, "abfarm873");
            case "android/os/Build->HARDWARE:Ljava/lang/String;":
                return new StringObject(vm, "qcom");
            case "android/os/Build->TAGS:Ljava/lang/String;":
                return new StringObject(vm, "release-keys");
            case "android/os/Build->FINGERPRINT:Ljava/lang/String;":
                return new StringObject(vm, "");
            case "android/os/Build->MANUFACTURER:Ljava/lang/String;":
                return new StringObject(vm, "Xiaomi");
            case "android/os/Build->SUPPORTED_ABIS:[Ljava/lang/String;":
                return ArrayObject.newStringArray(vm, "arm64-v8a", "armeabi-v7a", "armeabi");
        }
        return super.getStaticObjectField(vm, dvmClass, signature);
    }


    private String readAlttSP(String key){
        char[] cbuf = new char[0x1000];
        InputStreamReader input = null;
        try {
            input = new InputStreamReader(new FileInputStream(alttPath),"UTF-8");
            int len =input.read(cbuf);
            String text =new String(cbuf,0, len);
            JSONObject jsonobject = JSON.parseObject(text);
            return jsonobject.getString(key);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    private void writeAlttSP(String key, String value){
        char cbuf[] = new char[0x1000];
        InputStreamReader input;
        try {
            input = new InputStreamReader(new FileInputStream(new File(alttPath)),"UTF-8");
            int len =input.read(cbuf);
            String text =new String(cbuf,0, len);
            JSONObject jsonobject = JSON.parseObject(text);
            jsonobject.put(key, value);
            String result =JSON.toJSONString(jsonobject);
            try {
                BufferedWriter out = new BufferedWriter(new FileWriter(alttPath));
                out.write(result);
                out.close();
            } catch (IOException e) {
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public long getLongField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
        switch (signature){
            case "android/content/pm/PackageInfo->firstInstallTime:J":
                return 1661756946684L;
            case "android/content/pm/PackageInfo->lastUpdateTime:J":
                return 1661756946684L;
        }
        return super.getLongField(vm, dvmObject, signature);
    }

    @Override
    public int callIntMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature){
            case "android/content/Intent->getIntExtra(Ljava/lang/String;I)I": {
                String arg = vaList.getObjectArg(0).getValue().toString();
                switch (arg) {
                    case "temperature":
                        return 0x154;
                    case "level":
                        return 19;
                    case "status":
                        return 3;
                }
            }
            case "com/nike/mynike/MyNikeApplication->checkCallingOrSelfPermission(Ljava/lang/String;)I":{
                String key = vaList.getObjectArg(0).getValue().toString();
                System.out.println("check permission:"+key);
                switch (key) {
                    case "android.permission.INTERNET":
                        return 0;
                }
            }
            case "java/lang/reflect/Method->getModifiers()I":{
                return 1;
            }
            case "android/content/SharedPreferences->getInt(Ljava/lang/String;I)I":{
                String key = vaList.getObjectArg(0).getValue().toString();
                System.out.println("getint:"+key);
                String ret = readAlttSP(key);
                if(ret.equals("")){
                    return 0;
                }else {
                    return Integer.parseInt(ret);
                }

            }
            case "android/telephony/TelephonyManager->getPhoneCount()I":{
                return 2;
            }
            case "android/telephony/TelephonyManager->getSimState()I":{
                return 1;
            }
            case "android/telephony/TelephonyManager->getSimState(I)I":{
                return 1;
            }
            case "android/view/Display->getWidth()I":{
                return 1080;
            }
            case "android/view/Display->getHeight()I":{
                return 2160;
            }
        }
        return super.callIntMethodV(vm, dvmObject, signature, vaList);
    }

    @Override
    public int getStaticIntField(BaseVM vm, DvmClass dvmClass, String signature) {
        switch (signature){
            case "android/os/Build$VERSION->SDK_INT:I":
                return 29;
        }
        return super.getStaticIntField(vm, dvmClass, signature);
    }

    @Override
    public int callStaticIntMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature){
            case "com/aliyun/TigerTally/A->gs()I":{
                return 2;
            }
            case "com/aliyun/TigerTally/A->cf()I":{
                return 0;
            }
            case "android/provider/Settings$Global->getInt(Landroid/content/ContentResolver;Ljava/lang/String;I)I":{
                String arg = vaList.getObjectArg(1).getValue().toString();
                if(arg.equals("adb_enabled")){
                    return 0;
                }
            }
            case "java/lang/reflect/Array->getLength(Ljava/lang/Object;)I":{
                return 0;
            }
            case "android/provider/Settings$System->getInt(Landroid/content/ContentResolver;Ljava/lang/String;)I": {
                String tag = vaList.getObjectArg(1).getValue().toString();
                switch (tag) {
                    // https://developer.android.com/reference/android/provider/Settings.System#SCREEN_BRIGHTNESS
                    case "screen_brightness": {
                        return 45;
                    }
                }
            }
        }
        return super.callStaticIntMethodV(vm, dvmClass, signature, vaList);
    }

    @Override
    public boolean callStaticBooleanMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature){
            case "android/app/ActivityManager->isUserAMonkey()Z":{
                return false;
            }
            // 系统自带的检测debug
            case "android/os/Debug->isDebuggerConnected()Z":{
                return false;
            }
        }
        return super.callStaticBooleanMethodV(vm, dvmClass, signature, vaList);
    }

    @Override
    public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature){
            case "android/content/IntentFilter-><init>(Ljava/lang/String;)V":{
                System.out.println("IntentFilter:"+vaList.getObjectArg(0).getValue().toString());
                return dvmClass.newObject(null);
            }
            case "com/aliyun/TigerTally/A$AA-><init>()V":{
                return dvmClass.newObject(null);
            }
            case "com/aliyun/TigerTally/A$BB-><init>()V":{
                return dvmClass.newObject(null);
            }
            case "com/mediatek/telephony/TelephonyManagerEx-><init>(Landroid/app/Application;)V":{
                return null;
            }
            case "android/graphics/Point-><init>()V":{
                return dvmClass.newObject(signature);
            }
            case "com/mediatek/telephony/TelephonyManagerEx-><init>(Landroid/content/Context;)V":{
                return null;
            }
        }
        return super.newObjectV(vm, dvmClass, signature, vaList);
    }

    @Override
    public int getIntField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
        switch (signature){
            // 检查当前app是否是debug状态
            case "android/content/pm/ApplicationInfo->flags:I":{
                return 954777156;
            }
            case "android/graphics/Point->y:I":{
                return 2160;
            }
        }
        return super.getIntField(vm, dvmObject, signature);
    }

    @Override
    public DvmObject<?> getObjectField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
        switch (signature){
            case "java/lang/ClassLoader->pathList:Ldalvik/system/DexPathList;":{
                return vm.resolveClass("dalvik/system/DexPathList").newObject(null);
            }
            case "dalvik/system/DexPathList->dexElements:[Ldalvik/system/DexPathList$Element;":{
                return null;
            }
            case "dalvik/system/DexPathList->nativeLibraryDirectories:Ljava/util/List;":{
                return new ArrayListObject(vm, Collections.<DvmObject<?>>emptyList());
            }
            case "dalvik/system/PathClassLoader->pathList:Ldalvik/system/DexPathList;":{
                return null;
            }
        }
        return super.getObjectField(vm, dvmObject, signature);
    }

    private void hookBind() {
        long bindAddress = module.findSymbolByName("bind").getAddress();
        emulator.attach().addBreakPoint(bindAddress, new BreakPointCallback() {
            @Override
            public boolean onHit(Emulator<?> emulator, long address) {
                System.out.println("hook bind");
                RegisterContext registerContext = emulator.getContext();
                emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_PC, registerContext.getLRPointer().peer);
                emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0, -1);
                return true;
            }
        });
    }

    @Override
    public boolean callBooleanMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature){
            case "android/content/SharedPreferences$Editor->commit()Z":{
                return true;
            }
            case "android/net/wifi/WifiManager->isWifiEnabled()Z":{
                return false;
            }
        }
        return super.callBooleanMethodV(vm, dvmObject, signature, vaList);
    }

    @Override
    public void callVoidMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature){
            // 获取屏幕宽高
            // https://blog.csdn.net/joye123/article/details/80675328
            case "android/view/Display->getSize(Landroid/graphics/Point;)V":{
                return;
            }
            case "android/view/Display->getRealSize(Landroid/graphics/Point;)V":{
                return;
            }
        }
        super.callVoidMethodV(vm, dvmObject, signature, vaList);
    }

    @Override
    public long callStaticLongMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature){
            case "android/os/SystemClock->uptimeMillis()J":
                /* 自开机后，经过的时间，不包括深度休眠的时间*/
                return 59816853;
            case "android/os/SystemClock->elapsedRealtime()J":
                /*自开机后，经过的时间，包括深度休眠的时间*/
                return 89866853;
        }
        return super.callStaticLongMethodV(vm, dvmClass, signature, vaList);
    }
}
